package net.cyndeline.entitySystem.defaultImpl

import net.cyndeline.entitySystem.EntityRef
import net.cyndeline.entitySystem.EntityManager
import net.cyndeline.entitySystem.IdManager
import net.cyndeline.entitySystem.Component
import net.cyndeline.entitySystem.common.NullIterator
import net.cyndeline.entitySystem.Event
import language.postfixOps
import net.cyndeline.events.ModifyError
import com.escalatesoft.subcut.inject.BindingModule
import com.escalatesoft.subcut.inject.Injectable

class DefaultEntityRef(implicit val bindingModule: BindingModule) extends EntityRef with ModifyError with Injectable {
  private var privId = IdManager.NULL_ID
  private var entitymanager: EntityManager = inject[EntityManager]
  
  override def id: Int = privId
  
  override def id_=(setId: Int) {
    modify("id", this)
    privId = setId
  }
  
  override def entityManager_=(newManager: EntityManager) {
    modify("entity manager", this)
    entitymanager = newManager
  }
  
  override def entityManager = entitymanager
  
  override def exists = (id != IdManager.NULL_ID)
  
  override def getComponent[T <: Component](componentClass: Class[T]): Option[T] = {
    if (exists) {
      val componentOption = entitymanager.getComponent(id, componentClass)
      
      if (componentOption isDefined) {
        val component: Component = (componentOption get)
        Option(componentClass.cast(component))
      } else {
        None
      }
      
    } else {
      None
    }
  }
  
  override def addComponent[T <: Component](component: T): Option[T] = {
    if (exists) {
      Option(entitymanager.addComponent(id, component))
    } else {
      Option(component)
    }
  }
  
  override def removeComponent(componentClass: Class[_ <: Component]) {
    if (exists) {
      entitymanager.removeComponent(id, componentClass)
    }
  }
  
  override def iterateComponents: Iterator[Component] = {
    if (exists) {
      entitymanager.iterateComponents(id)
    } else {
      new NullIterator
    }
  }
  
  override def destroy {
    if (exists) {
      entitymanager.destroy(id)
    }
  }
  
  override def send(event: Event) {
    if (exists) {
      entitymanager.eventSystem match {
        case Some(system) => system.deliverEvent(this, event)
        case None => {}
      }
    }
  }
  
  override def hasComponent(componentClass: Class[_ <: Component]): Boolean = {
    exists && entitymanager.hasComponent(id, componentClass)
  }
  
  override def equals(other: Any): Boolean = {    
    val result: Boolean = other match {
      case d: DefaultEntityRef => id == d.id || this.eq(d)
      case e: EntityRef => (!exists && !(e exists))
      case _ => false
    }
    
    result
  }
  
  override def hashCode: Int = {
    if (!exists) {
      0
    } else {
      (id ^ (id >>> 32))
    }
  }
  
  override def toString: String = {
    "EntityRef{id=" + id + "}"
  }
  
  override def invalidate {
    privId = IdManager.NULL_ID
  }
  
  override def copy(): EntityRef = entitymanager.copy(this)
}